<template>
  <div class="h-full" :class="prefixCls">
    <FlowChartToolbar :prefixCls="prefixCls" v-if="toolbar" @view-data="handlePreview" />
    <div ref="lfElRef" class="h-full"></div>
    <BasicModal @register="register" ok-text="保存" :destroy-on-close="true" @ok="handleSave">
      <BasicForm @register="registerForm" />
    </BasicModal>
  </div>
</template>
<script lang="ts" setup>
  import type { Ref } from 'vue';
  import type { Definition } from '@logicflow/core';
  import { ref, onMounted, unref, nextTick, computed, watch } from 'vue';
  import FlowChartToolbar from './FlowChartToolbar.vue';
  import LogicFlow from '@logicflow/core';
  import { Snapshot, BpmnElement, Menu, DndPanel, SelectionSelect } from '@logicflow/extension';
  import { useDesign } from '/@/hooks/web/useDesign';
  import { useAppStore } from '/@/store/modules/app';
  import { createFlowChartContext } from './useFlowContext';
  import { toLogicFlowData } from './adpterForTurbo';
  import { useModal, BasicModal } from '/@/components/Modal';
  import { BasicForm, useForm } from '/@/components/Form';
  import { configDefaultDndPanel } from './config';
  import TBRect from './TBRect';
  import TBEdge from './TBEdge';
  import '@logicflow/core/dist/style/index.css';
  import '@logicflow/extension/lib/style/index.css';
  import { modalFormStyleSetting, modalStyleSetting } from '/@/settings/thingsBoardDesign';
  import { processSchemas } from './TBRect';

  const props = defineProps({
    flowOptions: {
      type: Object as PropType<Definition>,
      default: () => ({}),
    },

    data: {
      type: Object as PropType<any>,
      default: () => ({}),
    },

    toolbar: {
      type: Boolean,
      default: true,
    },
    patternItems: {
      type: Array,
    },
  });
  const lfElRef = ref(null);
  const graphData = ref({});

  const lfInstance = ref(null) as Ref<LogicFlow | null>;
  const [registerForm, { setProps, setFieldsValue, validate, updateSchema }] = useForm({
    layout: 'vertical',
    actionColOptions: {
      span: 24,
    },
    showActionButtonGroup: false,
    ...modalFormStyleSetting,
  });
  const { prefixCls } = useDesign('flow-chart');
  const appStore = useAppStore();
  const [register, { openModal, setModalProps, closeModal }] = useModal();
  const selectedId = ref('');

  createFlowChartContext({
    logicFlow: lfInstance as unknown as LogicFlow,
  });

  const getFlowOptions = computed(() => {
    const { flowOptions } = props;

    const defaultOptions: Partial<Definition> = {
      grid: true,
      background: {
        color: appStore.getDarkMode === 'light' ? '#f7f9ff' : '#151515',
      },
      keyboard: {
        enabled: true,
      },
      ...flowOptions,
    };
    return defaultOptions as Definition;
  });

  watch(
    () => props.data,
    () => {
      onRender();
    },
  );

  // TODO
  // watch(
  //   () => appStore.getDarkMode,
  //   () => {
  //     init();
  //   }
  // );

  watch(
    () => unref(getFlowOptions),
    (options) => {
      unref(lfInstance)?.updateEditConfig(options);
    },
  );

  // init logicFlow
  async function init() {
    await nextTick();

    const lfEl = unref(lfElRef);
    if (!lfEl) {
      return;
    }
    LogicFlow.use(DndPanel);

    // Canvas configuration
    LogicFlow.use(Snapshot);
    // Use the bpmn plug-in to introduce bpmn elements, which can be used after conversion in turbo
    LogicFlow.use(BpmnElement);
    // Start the right-click menu
    LogicFlow.use(Menu);
    LogicFlow.use(SelectionSelect);

    lfInstance.value = new LogicFlow({
      ...unref(getFlowOptions),
      container: lfEl,
      nodeTextEdit: false,
    });
    lfInstance.value.register(TBRect);
    lfInstance.value.register(TBEdge);
    const lf = unref(lfInstance)!;
    // 节点增加
    lf.on('node:dnd-add', ({ data }) => {
      const { properties, id, text } = data;
      setModalProps({
        title: `添加规则节点：${data.text.value}`,
        ...modalStyleSetting,
      });
      selectedId.value = id;
      openModal(true);
      setTimeout(() => {
        const schemas = processSchemas(text.value, properties.schema);
        setProps({
          schemas,
        });
      }, 12);
    });
    // 边线增加
    lf.on('edge:add', ({ data }) => {
      const { properties, id, text } = data;

      setModalProps({
        title: `添加规则节点：${data.text.value}`,
        ...modalStyleSetting,
      });
      selectedId.value = id;
      openModal(true);
      setTimeout(() => {
        const schemas = processSchemas(text.value, properties.schema);
        setProps({
          schemas,
        });
      }, 12);
    });
    lf.on('node:dbclick,edge:dbclick', ({ data }) => {
      const { properties, id, text } = data;
      if (properties.type == 'input') return;
      setModalProps({
        title: `添加规则节点：${data.text.value}`,
        ...modalStyleSetting,
      });
      selectedId.value = id;
      openModal(true);
      setTimeout(() => {
        const schemas = processSchemas(text.value, properties.schema);
        setProps({
          schemas,
        });
        setFieldsValue({
          ...properties.data,
        });
      }, 10);
    });

    lf?.setDefaultEdgeType('sequence');
    onRender();
    lf?.setPatternItems(props.patternItems || configDefaultDndPanel(lf));
  }

  async function onRender() {
    await nextTick();
    const lf = unref(lfInstance);
    if (!lf) {
      return;
    }
    const lFData = toLogicFlowData(props.data);
    lf.render(lFData);
  }

  function handlePreview() {
    const lf = unref(lfInstance);
    if (!lf) {
      return;
    }
    graphData.value = unref(lf).getGraphData();
    openModal();
  }

  const handleSave = async () => {
    try {
      const values = await validate();
      const lf = unref(lfInstance);
      if (!lf) {
        return;
      }
      const data = lf.getGraphData();
      data.nodes.forEach((item) => {
        if (item.id == selectedId.value) {
          item.properties.data = values;
          lf.setProperties(item.id, item.properties);
        }
      });
      closeModal();
    } catch (error) {}
  };
  onMounted(init);
</script>

<style lang="less" scoped>
  :deep(.lf-dnd-shape) {
    display: none;
  }
</style>
